using System;
using System.Collections.Generic;
using Clandestine.Base;
using Clandestine.Graphics;
using System.Xml;

namespace Clandestine.Engines.Field
{
	// IWatchable: Changes on AddLevel()
	public class Map : IWatchable
	{
		public int GridSize { get; private set; }
		public string Name { get; set; }
		public string Filename { get; private set;}
		public List<Level> Levels;
		public Clandestine.Graphics.Graphics Graphics { get; private set; }
		public Spritesheets Spritesheets { get; private set; }
		public event Changed Changed;
		
		internal Map(Clandestine.Graphics.Graphics g)
		{
			this.Graphics = g;	
			this.Levels = new List<Level>();
			this.Spritesheets = new Spritesheets(this);
		}
		public Map(Clandestine.Graphics.Graphics g, int gridSize) : this(g)
		{
			this.GridSize = gridSize;
			this.Name = "Untitled Map";
			this.Filename = "untitled.xml";
		}
		public Map(Clandestine.Graphics.Graphics g, string name, int gridSize) : this(g, gridSize)
		{
			this.Name = name;
		}
		public Map(Clandestine.Graphics.Graphics g, string filename) : this(g)
		{
			this.Load(filename);
		}

		public void AddLevel(Level l)
		{
			lock (Levels)
				this.AddLevel(l, this.Levels.Count); // add on 'top'
		}
		public void AddLevel(Level l, int depth)
		{
			lock (Levels)
			{
				Levels.Insert(depth, l);	
				
				if (this.Changed != null)
					Changed(this);
			}
		}
	
		public void Load(string filename)
	 	{
	 		this.Load(XmlReader.Create(filename));
	 		this.Filename = filename;
		}
		internal void Load(XmlReader xml)
		{
			// Get to start of map! -- probs redundant
			while (((xml.NodeType != XmlNodeType.Element) || (xml.Name != "map")) && xml.Read());
			if (xml.EOF)
				throw new Exception("No <map> in given file.");
				
			// Get Attributes
			this.Name = xml.GetAttribute("name");
			this.GridSize = int.Parse(xml.GetAttribute("gridSize"));
			
			// Remapping to map the numbers used in the file for spritesheets to what they've been loaded as
			Dictionary<int, int> remapping = new Dictionary<int, int>(); 
			
			// And everything else
			while (xml.Read())
			{
				if (xml.NodeType == XmlNodeType.Element)
                {
                    switch (xml.Name)
                    {
                    	case "spritesheets":
                    		remapping = this.Spritesheets.Load(xml);
                    		break;
						case "level":
							if (remapping.Count == 0)
								throw new Exception("Loading <level> before <spritesheets>! (maybe empty <spritesheets>?)");
						
							Level l = new Level(this.Graphics, this);
							l.Load(xml, remapping);
							this.AddLevel(l);
							break;
                    }
               	} else if ((xml.NodeType == XmlNodeType.EndElement) && (xml.Name == "map"))
                	return;
			}
		}
		
		public void RedrawDirty()
		{
			lock (Levels)
				foreach (Level l in Levels)
					l.RedrawDirty();
		}
	}
}

